Cloud Functions実行環境で「rm -rf /*」を実行してみた
MAD事業部@大阪の岩田です。
本エントリは クラスメソッド Google Cloud Advent Calendar 2021 の 24日目 の記事です。
最近色んな環境でrm -rf /*
を実行するのが流行っているようですね。
このビッグウェーブに乗るべくGoogle CloudのCloud Functions実行環境でrm -rf /*
を試してみたいと思います。
やってみる
早速やっていこうと思うのですが、OSコマンドの実行を試すためにいちいちCloud Functionsにデプロイするソースコードを書き換えてデプロイして...を繰り返すのは効率が悪そうです。理想としてはCloud Functions実行環境にシェルアクセスして各種コマンドで環境を自由に分析し、最後にrm -rf /*
を実行できると嬉しいです。
ということで、以前紹介したserverless-preyを利用してCloud Functions実行環境にシェルアクセスできる環境を構築します。
Cheetahのデプロイ
serverless-preyはnetcatとngrokを利用して各FaaSプラットフォーム向けにシェルアクセスを提供する関数のコレクションです。Google CloudのCloud Functions向けにはCheetahを利用します。
まずはGitHubからserverless-preyのリポジトリをクローンします
$ git clone https://github.com/pumasecurity/serverless-prey.git
続いて以下のコマンドでCheetahをデプロイします
$ cd serverless-prey/cheetah/src/cheetah/ $ gcloud functions deploy cheetah --entry-point Cheetah --runtime go111 --trigger-http --memory=8192MB --timeout=540
ランタイムにはGo 1.11を指定しています。現在は非推奨のバージョンですが、1.13に上げてしまうとCheetahが動作しません。メモリとタイムアウト値はrm -rf/*
の実行時間を考慮して最大値を指定しておきます。
以下のように出力されればデプロイ完了です。
WARNING: The go111 runtime is deprecated on Cloud Functions. Please migrate to a newer Golang version (--runtime=go113). Allow unauthenticated invocations of new function [cheetah]? (y/N)? WARNING: Function created with limited-access IAM policy. To enable unauthorized access consider `gcloud alpha functions add-iam-policy-binding cheetah --region=us-central1 --member=allUsers --role=roles/cloudfunctions.invoker` Deploying function (may take a while - up to 2 minutes)...⠛ For Cloud Build Logs, visit: https://console.cloud.google.com/cloud-build/builds;region=us-central1/05f0d094-36e0-40cf-9a55-d21da4eeb3ff?project=<GCPのプロジェクトID> Deploying function (may take a while - up to 2 minutes)...done. availableMemoryMb: 8192 buildId: 05f0d094-36e0-40cf-9a55-d21da4eeb3ff buildName: projects/<GCPのプロジェクトID>/locations/us-central1/builds/05f0d094-36e0-40cf-9a55-d21da4eeb3ff entryPoint: Cheetah httpsTrigger: securityLevel: SECURE_ALWAYS url: https://us-central1-<GCPのプロジェクト名>.cloudfunctions.net/cheetah ingressSettings: ALLOW_ALL labels: deployment-tool: cli-gcloud name: projects/GCPのプロジェクト名/locations/us-central1/functions/cheetah runtime: go111 serviceAccountEmail: <GCPのプロジェクト名>@appspot.gserviceaccount.com sourceUploadUrl: https://storage.googleapis.com/gcf-upload-us-central1-8c61bdd9-3f4a-4b01-aaf6-ed74d76df6f0/9d6e145d-4944-499b-a753-ad0f79bbbb99.zip status: ACTIVE timeout: 540s updateTime: '2021-12-21T13:04:30.319Z' versionId: '1'
Cloud Functions実行環境にシェルアクセスしてみる
関数の準備ができたのでserverless-preyのスクリプトを使ってCloud Functions実行環境にシェルアクセスしてみます。※serverless-preyはncとngrokを利用するので両コマンドを事前にインストールしておいて下さい。
まず関数を呼び出すために必要なIDトークンを取得します。
$export GCLOUD_ID_TOKEN=$(gcloud config config-helper --format=json | jq -r '.credential.id_token')
取得したIDトークンを使って関数を起動しつつngrokとncを使って自分のローカル環境からシェルアクセスしましょう。./script/prey.sh
というシェルスクリプトが諸々の処理を実行してくれるので、このスクリプトに関数のトリガーURLとIDトークンを渡して関数を起動します。
$ ./script/prey.sh cheetah --url <デプロイした関数のトリガーURL> --api-key $GCLOUD_ID_TOKEN
しばらくすると以下のように出力されプロンプトの>
が表示されます。
@@@@@@@@((. ((@@@@@@@@ *@@@@@@(/*#@%, %&@(*/(@@@@@@/ (@@@@@(*.#%&@*/( //*@&%#.*(@@@@@( /@@@@@(***//(&&&%. .%&&&(//***(@@@@@% #&@@@@@@&&&&&&&&& %&&&&&&&&@@@@@@&# Serverless Prey https://github.com/pumasecurity/serverless-prey >
これで...Cloud Functions実行環境でコマンド実行し放題!!まずはウォーミングアップでいくつかコマンドを実行してみましょう
ls go.mod go.sum main.go serverless_function_source_code pwd /workspace whoami www-data uname -a Linux localhost 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 x86_64 x86_64 GNU/Linux hostname localhost ip a 2: eth0: <UP,LOWER_UP> mtu 65000 link/none 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 169.254.8.130/32 scope global dynamic 3: eth1: <UP,LOWER_UP> mtu 1280 link/none 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 169.254.8.1/32 scope global dynamic inet6 fddf:3978:feb1:d745::c001/128 scope global dynamic 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 link/loopback 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff inet6 ::1/128 scope global dynamic inet 127.0.0.1/8 scope global dynamic dmesg [ 0.000000] Starting gVisor... [ 0.201683] Creating cloned children... [ 0.376652] Checking naughty and nice process list... [ 0.622287] Moving files to filing cabinet... [ 0.989163] Mounting deweydecimalfs... [ 1.263683] Constructing home... [ 1.645722] Digging up root... [ 1.803795] Reticulating splines... [ 2.065709] Consulting tar man page... [ 2.263922] Checking naughty and nice process list... [ 2.331320] Creating process schedule... [ 2.814881] Ready!
なるほどなるほど。ウォーミングアップ完了です。
rm -rf /*を実行してみる
ウォーミングアップできたら本題であるrm -rf /*
を実行しましょう。自分が操作しているシェルがCloud Functions実行環境のシェルであることを入念にチェックしてから実行して下さい
rm -rf /* rm: cannot remove '/bin/bash': Read-only file system rm: cannot remove '/bin/bunzip2': Read-only file system rm: cannot remove '/bin/bzcat': Read-only file system rm: cannot remove '/bin/bzcmp': Read-only file system rm: cannot remove '/bin/bzdiff': Read-only file system rm: cannot remove '/bin/bzegrep': Read-only file system rm: cannot remove '/bin/bzexe': Read-only file system rm: cannot remove '/bin/bzfgrep': Read-only file system rm: cannot remove '/bin/bzgrep': Read-only file system rm: cannot remove '/bin/bzip2': Read-only file system rm: cannot remove '/bin/bzip2recover': Read-only file system rm: cannot remove '/bin/bzless': Read-only file system rm: cannot remove '/bin/bzmore': Read-only file system rm: cannot remove '/bin/cat': Read-only file system ...略
動き始めました。リアルタイムに出力を確認できるのがシェルアクセスの良いところですね。肝心の実行結果は?というと...予想通りですが権限が無いため何も削除できていないようです。
ドキュメント上の明確な記述が見つけられなかったのですが、各種情報を調べた限り、Cloud Functions実行環境で書き込みが許可されているのは/tmp
ディレクトリ以下のみのようです。このあたりはAWS Lambdaのような他のFaaSでも同様ですね。
しばらく待つと以下のような出力で止まってしまいました。
rm: cannot remove '/workspace/serverless_function_source_code/Makefile': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/cheetah.go': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/cheetah.yaml': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/go.mod': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/go.sum': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/package-lock.json': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/package.json': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/resources.yml': Read-only file system rm: cannot remove '/workspace/serverless_function_source_code/serverless.yml': Read-only file system rm: cannot remove '/www-data-home': Read-only file system Connection terminated.
関数のタイムアウト値は540秒に設定していたのですが、1分も待たずに出力が止まったのが意外なところでした。Cloud Loggingのログを確認すると以下のように出力されていました。約332秒後に500エラーで終了しているようです。
Function execution took 332805 ms, finished with status code: 500
試しに実行するコマンドをrm -rf /*
からsleep 540
に変えてみたところCloud Loggingのログは以下のように出力されました。
Function execution took 540003 ms, finished with status: 'timeout'
こちらはタイムアウト値の540秒とほぼイコールですね。なぜrm -rf /*
の場合はタイムアウト時間を待たずに異常終了してしまったのかは謎のままです。。。
まとめ
Cloud Functionsの実行環境でrm -rf /*
を実行しても何も削除されないことが分かりました。FaaSという特性を考えれば当然の結果と言えるでしょう。実際には自分で/tmp
配下に書き込んだファイルであれば削除可能ですが、まあ所詮は/tmp
なので実行環境が壊れることはありません。うっかりrm -rf /*
しても大丈夫なFaaSは安心して使えるコンピューティング基盤と言えますね。(まあ普通はFaaSの実行環境にシェルアクセスしたりコードからrm -rf /*することは無いのですが...)
アドベントカレンダー最終日である明日 12/25 は 田中孝明 さんによる「何かしらの手段でクリスマスを爆発させる(仮」です。私はCloud Functions実行環境の爆発に失敗してしまいましたが、田中さんには期待したいところです。お楽しみに!